﻿// MyProject.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//公众号：程序员速成 ，内含一辈子都让你感激自己的优质视频教程，欢迎关注

#include <iostream>
#include <atomic> //#include的头文件加在源文件顶部位置
#include <mutex>

#ifdef _DEBUG   //只在Debug（调试）模式下
#ifndef DEBUG_NEW
#define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__) //重新定义new运算符
#define new DEBUG_NEW
#endif
#endif

//#include <boost/type_index.hpp>
using namespace std;
//#pragma warning(disable : 4996) 

namespace _nmsp1
{
	//懒汉式（很懒惰之意）——程序执行后该单件类对象并不存在，只有第一次调用getInstance成员函数时该单件类对象才被创建
	class GameConfig
	{
		//......
	private:
		GameConfig() {};
		GameConfig(const GameConfig& tmpobj);
		GameConfig& operator=(const GameConfig& tmpobj);
		~GameConfig() {}
	public:
		static GameConfig* getInstance()
		{
			//std::lock_guard<std::mutex> gcguard(my_mutex);  粗暴加锁，不建议采用
			if (m_instance == nullptr)
			{
				//这里加锁（双重锁定/双重检查）——潜在问题：内存访问重新排序（重新排列编译器产生的汇编指令）导致双重锁定失效问题。 volatile。
				//std::lock_guard<std::mutex> gcguard(my_mutex);
				//if (m_instance == nullptr)  //if(m_instance != nullptr)
				//{
				static Garbo garboobj;
				m_instance = new GameConfig();
				//}
			}
			return m_instance;
		}

		/*
	public:
		static void freeInstance()
		{
			if (m_instance != nullptr)
			{
				delete GameConfig::m_instance;
				GameConfig::m_instance = nullptr;
			}
		}*/

	private:
		//手工释放单件类对象引入的GameConfig类中的嵌套类（垃圾回收）
		class Garbo
		{
		public:
			~Garbo()
			{
				if (GameConfig::m_instance != nullptr)
				{
					delete GameConfig::m_instance;
					GameConfig::m_instance = nullptr;
				}
			}
		};

	private:
		static GameConfig* m_instance; //指向本类对象的指针
	};
	GameConfig* GameConfig::m_instance = nullptr; //在类外，某个.cpp源文件的开头位置，为静态成员变量赋值（定义并赋值）
}
namespace _nmsp2
{
	//新版本，解决双重锁定导致的问题
	//游戏配置相关类 
	class GameConfig
	{
	private:
		GameConfig() {};
		GameConfig(const GameConfig& tmpobj);
		GameConfig& operator = (const GameConfig& tmpobj);
		~GameConfig() {};
	public:
		static GameConfig* getInstance()
		{
			GameConfig* tmp = m_instance.load(std::memory_order_relaxed);
			std::atomic_thread_fence(std::memory_order_acquire);
			if (tmp == nullptr)
			{
				std::lock_guard<std::mutex> lock(m_mutex);
				tmp = m_instance.load(std::memory_order_relaxed);
				if (tmp == nullptr)
				{
					tmp = new GameConfig();
					std::atomic_thread_fence(std::memory_order_release);
					m_instance.store(tmp, std::memory_order_relaxed);
				}
			}
			return tmp;
		}
	private:
		static atomic<GameConfig*> m_instance;
		static std::mutex m_mutex;
	};
	std::atomic<GameConfig*> GameConfig::m_instance;
	std::mutex GameConfig::m_mutex;

}
namespace _nmsp3
{
	//饿汉式（很饥渴很迫切之意）——程序一致性，不管是否调用了getInstance成员函数，这个单件类就已经被创建了(对象创建不受多线程问题困扰)。
	class GameConfig
	{
		//......
	private:
		GameConfig() {};
		GameConfig(const GameConfig& tmpobj);
		GameConfig& operator=(const GameConfig& tmpobj);
		~GameConfig() {}
	public:
		static GameConfig* getInstance()
		{			
			return m_instance;
		}
	
	private:
		//手工释放单件类对象引入的GameConfig类中的嵌套类（垃圾回收）
		class Garbo
		{
		public:
			~Garbo()
			{
				if (GameConfig::m_instance != nullptr)
				{
					delete GameConfig::m_instance;
					GameConfig::m_instance = nullptr;
				}
			}
		};
	private:
		static Garbo garboobj;

	private:
		static GameConfig* m_instance; 
	};
	GameConfig* GameConfig::m_instance = new GameConfig(); //趁静态成员变量定义的时候直接初始化是允许的，及时GameConfig构造函数是用private修饰
	GameConfig::Garbo GameConfig::garboobj;

	//int g_test = GameConfig::getInstance()->m_i; //m_i为一个int型成员变量
}
namespace _nmsp4
{
	//也相当于饿汉式编码方式
	class GameConfig
	{
		//......
	private:
		GameConfig() {};
		GameConfig(const GameConfig& tmpobj);
		GameConfig& operator=(const GameConfig& tmpobj);
		~GameConfig() {}
	public:
		static GameConfig* getInstance()
		{			
			return &m_instance;
		}

	private:
		static GameConfig m_instance; 
	};
	GameConfig GameConfig::m_instance;

	//int g_test = GameConfig::getInstance()->m_i;
}
namespace _nmsp5
{	
	class GameConfig
	{
		//......
	private:
		GameConfig() {};
		GameConfig(const GameConfig& tmpobj);
		GameConfig& operator=(const GameConfig& tmpobj);
		~GameConfig() {}
	public:
		static GameConfig& getInstance()
		{
			static GameConfig instance; //注意区别   函数第一次执行时被初始化的静态变量             与 
			                            //           通过编译期常量进行初始化的基本类型静态变量
			return instance;
		}	
	};	
}

int myfunc()
{
	static int stcs = 100;  //不需要调用myfunc函数，stcs就已经等于100了
	stcs += 180;
	return stcs;
}

int main()
{
	//myfunc();

	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口
	
	//第7章  单件（Singleton）模式
	//单例模式/单态模式：创建型模式，创建只能产生一个对象实例的类——用私有构造函数实现类的定义。
	//（1）单件类的基本概念和实现
	//GameConfig,Scott Meyers“要使接口或者类型易于正确使用，难以错误使用”
	//只能创建一个属于该类对象的类就称为单件类。
	//（2）单件类在多线程中可能导致的问题
	//一个好的解决多线程创建GameConfig类对象问题的方法是在main主函数中（程序执行入口中），在创建任何其他线程之前，
	  //先执行一次GameConfig::getInstance();来把这个单独的GameConfig类对象创建出来。
	//（3）饿汉式与懒汉式
	//（4）单件类对象内存释放问题
	//（5）单件类定义、UML图及另外一种实现方法
	//单件设计模式定义：保证一个类仅有一个实例存在，同时提供能对该实例访问的全局方法（getInstance成员函数）。
	//困扰的问题：多个单件类之间的相互引用个问题。 Log、GameConfig——不要在单件类的析构函数中引用其他单件类对象。



	/*
	_nmsp1::GameConfig g_config1;
	_nmsp1::GameConfig g_config2;
	*/

	/*
	_nmsp1::GameConfig* g_gc = _nmsp1::GameConfig::getInstance();
	_nmsp1::GameConfig* g_gc2 = _nmsp1::GameConfig::getInstance();
	*/



	//_nmsp1::GameConfig g_config1;
	//_nmsp1::GameConfig* g_gct = new _nmsp1::GameConfig;
	//_nmsp1::GameConfig g_gc3(*g_gc);
	//(*g_gc2) = (*g_gc);
	//delete g_gc;

	//_nmsp1::GameConfig::freeInstance();

	_nmsp5::GameConfig& g_gc40 = _nmsp5::GameConfig::getInstance();
	
	return 0;
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件


/*
#include <atomic> //#include的头文件加在源文件顶部位置
#include <mutex>
//游戏配置相关类 
class GameConfig
{
private:
	GameConfig() {};
	GameConfig(const GameConfig& tmpobj);
	GameConfig& operator = (const GameConfig& tmpobj);
	~GameConfig() {};
public:
	static GameConfig* getInstance()
	{
		GameConfig* tmp = m_instance.load(std::memory_order_relaxed);
		std::atomic_thread_fence(std::memory_order_acquire);
		if (tmp == nullptr)
		{
			std::lock_guard<std::mutex> lock(m_mutex);
			tmp = m_instance.load(std::memory_order_relaxed);
			if (tmp == nullptr)
			{
				tmp = new GameConfig();
				std::atomic_thread_fence(std::memory_order_release);
				m_instance.store(tmp, std::memory_order_relaxed);
			}
		}
		return tmp;
	}
private:
	static atomic<GameConfig*> m_instance;
	static std::mutex m_mutex;
};
std::atomic<GameConfig*> GameConfig::m_instance;
std::mutex GameConfig::m_mutex;

*/